#include "stdafx.h"
#include "TestRunner.h"
#include "Test.h"
#include "TestSuite.h"
#include "TextTestResult.h"
#include <iostream>

namespace JHCPP{
	namespace CppUnit{

		CTestRunner::CTestRunner():
			_ostr(std::cout)
		{
		}

		CTestRunner::CTestRunner(std::ostream& ostr):
			_ostr(ostr)
		{
		}

		CTestRunner::~CTestRunner()
		{
			for (Mappings::iterator it = _mappings.begin(); it != _mappings.end(); ++it)
				delete it->second;
		}

		void CTestRunner::printBanner()
		{
			_ostr 
				<< "Usage: driver [-all] [-print] [-wait] [name] ..." << std::endl
				<< "       where name is the name of a test case class" << std::endl;
		}

		bool CTestRunner::run(const std::vector<std::string>& args)
		{
			std::string testCase;
			int numberOfTests = 0;
			bool success = true;
			bool all     = false;
			bool wait    = false;
			bool printed = false;

			for (size_t i = 1; i < args.size(); i++) 
			{
				const std::string& arg = args[i];
				if (arg == "-wait") 
				{
					wait = true;
					continue;
				}
				else if (arg == "-all")
				{
					all = true;
					continue;
				}
				else if (arg == "-print")
				{
					for (Mappings::iterator it = _mappings.begin(); it != _mappings.end(); ++it) 
					{
						print(it->first, it->second, 0);
					}
					printed = true;
					continue;
				}

				if (!all)
				{
					testCase = arg;

					if (testCase == "")
					{
						printBanner();
						return false;
					}

					CTest* testToRun = 0;
					for (Mappings::iterator it = _mappings.begin(); !testToRun && it != _mappings.end(); ++it) 
					{
						testToRun = find(testCase, it->second, it->first);
					}
					if (testToRun)
					{
						if (!run(testToRun)) success = false;
					}
					numberOfTests++;

					if (!testToRun) 
					{
						_ostr << "Test " << testCase << " not found." << std::endl;
						return false;
					}
				}
			}

			if (all)
			{
				for (Mappings::iterator it = _mappings.begin(); it != _mappings.end(); ++it) 
				{
					if (!run(it->second)) success = false;
					numberOfTests++;
				}
			}
			
			if (numberOfTests == 0 && !printed) 
			{
				printBanner();
				return false;
			}

			if (wait) 
			{
				_ostr << "<RETURN> to continue" << std::endl;
				std::cin.get();
			}

			return success;
		}

		bool CTestRunner::run(CTest* test)
		{
			CTextTestResult result(_ostr);

			test->run(&result);
			_ostr << result << std::endl;

			return result.wasSuccessful();
		}

		void CTestRunner::addTest(const std::string& name, CTest* test)
		{
			_mappings.push_back(Mapping(name, test));
		}

		void CTestRunner::print(const std::string& name, CTest* pTest, int indent)
		{
			for (int i = 0; i < indent; ++i)
				_ostr << "    ";
			_ostr << name << std::endl;
			CTestSuite* pSuite = dynamic_cast<CTestSuite*>(pTest);
			if (pSuite)
			{
				const std::vector<CTest*>& tests = pSuite->tests();
				for (std::vector<CTest*>::const_iterator it = tests.begin(); it != tests.end(); ++it)
				{
					print((*it)->toString(), *it, indent + 1);
				}
			}
		}

		CTest* CTestRunner::find(const std::string& name, CTest* pTest, const std::string& testName)
		{
			if (testName.find(name) != std::string::npos)
			{
				return pTest;
			}
			else
			{
				CTestSuite* pSuite = dynamic_cast<CTestSuite*>(pTest);
				if (pSuite)
				{
					const std::vector<CTest*>& tests = pSuite->tests();
					for (std::vector<CTest*>::const_iterator it = tests.begin(); it != tests.end(); ++it)
					{
						CTest* result = find(name, *it, (*it)->toString());
						if (result) return result;
					}
				}
				return 0;
			}
		}

	}//end of namespace CppUnit
}//end of namespace JHCPP
